//-----------------------------------------------------------------------------
//
// @file	LevelSet.h
// @brief	Transform include files, variables and classes
// @author	Vinod Melapudi
// @date	13Aug2011
//
//-----------------------------------------------------------------------------

#ifndef _LEVELSET_H
#define _LEVELSET_H

#include "Utils.h"
#include "Mesh.h"
#include "Vector3T.h"
#include "Octree.h"

class Scene;
class Renderer;
class MemPool;


// An external vector field can be applied on levelset, modifying the levelset values, inturn moving the front
// Callback function to get vector field value
typedef bool(*VectorFieldFn)( const uLocation& l, Vector3& value );


//
// Level Set - Signed distance grid class
//
class LevelSet
{
public:

	// Info node: has signed distance value (and probably tag for narrow or near band)
	struct InfoNode
	{
		float	value;
		float	new_value;
	};


	// Callback function to apply an operation on a cell with given param (Kernel function)
	struct CellOpParam
	{
		LevelSet*			level_set;				// Ptr to level set class
		uLocation			location;				// x, y, z index to the cell
		LevelSet::InfoNode* info_node;				// Info node of the cell
		void*				user_data;				// User param
	};
	typedef void (*CellOperationFn)( const CellOpParam& param );




public:
	LevelSet();
	~LevelSet();

	// Accessors
	Vector3		GetCellSize() const		{ return m_cell_size; }

	void	SetValue( const uLocation& l, float value );
	
	template<class T>	
	bool	GetValue( const uLocation& l, T &value );

	
	// Normalize the levelset
	void	Normalize();

	// Reset levelset
	void	Reset();


	// Initalizing fns
	void	SetSphere( float radius, float cell_size );


	// Grow level set by given factor in normal direction
	void	Grow( float factor );

	// An external vector field can be applied on levelset, modifying the levelset values, inturn moving the front
	// Provide function to get vector field values at given grid point
	void	ApplyVectorField( VectorFieldFn fn );


	// Apply kernel function
	void	ApplyFn( CellOperationFn fn, void* user_data=NULL );


	// Render level set to mesh
	void	RenderToMesh( Mesh& mesh );

	// Render grid
	void	RenderGrid( Renderer* renderer=NULL, Scene* scene=NULL );
	void	MoveHighlightCell( const uLocation& move_by );

private:

	// Kernel functions
	static void		GrowCellFn( const CellOpParam& param );
	static void		ApplyVectorFieldCellFn( const CellOpParam& param );
	static void		NormalizeCellFn( const CellOpParam& param );
	static void		ReplaceValueCellFn( const CellOpParam& param );
	static void		RenderToMeshCellFn( const CellOpParam& param );
	static void		RenderGridCellFn( const CellOpParam& param );


	// Allocate info node and fills the node with given values
	InfoNode*	AllocateInfoNode( float value );

	// Helper functions to get cell values
	InfoNode*	GetInfoNode( const uLocation& l );
	bool		GetNeighbourValuesNoOpt( const uLocation& l, float& node_value, Vector3 *pos_values, Vector3 *neg_values=NULL, Vector4 *diag_values=NULL );
	bool		GetNeighbourValues( const uLocation& l, float& node_value, Vector3 *pos_values, Vector3 *neg_values=NULL, Vector4 *diag_values=NULL );
	bool		GetNeighbourDiff( const uLocation& l, Vector3 &pos_diff, Vector3 &neg_diff );
	bool		CalcGradientLength( const uLocation& l, float factor, float &gradient_length );

private:

	// Octtree data structure
	Octree<InfoNode*>*	m_octree;

	// Cell size of grid
	Vector3		m_cell_size;
	
	// Highlight cell
	uLocation	m_highlighted_cell;

	// Mempool
	MemPool		*m_mem_info_pool;
};

#endif